#include <multivector.h>
#define BOOST_TEST_MODULE CnomeMultivectorTest
#include <boost/test/unit_test.hpp>

using namespace cnome::infra;

typedef multivector<int> multivector_testT;


BOOST_AUTO_TEST_CASE(CnomeMultivectorTest) {
    multivector_testT a;  // Instantiation test

    // Empty tests
    BOOST_CHECK(a.begin() == a.end());
    BOOST_CHECK(a.rbegin() == a.rend());

    multivector_testT::position_type mp;
    mp.push_back(0);
    a[mp] = 2; // {{[0],2}}
    BOOST_CHECK(a[mp] == 2);

    multivector_testT::iterator it = a.begin();
    BOOST_CHECK(it->second == 2);

    ++it;
    BOOST_CHECK(it == a.end());

    multivector_testT::reverse_iterator rit = a.rbegin();
    BOOST_CHECK(rit->second == 2);

    ++rit;
    BOOST_CHECK(rit == a.rend());

    mp[0] = 1;
    a[mp] = 3; // {{[0], 2}, {[1], 3}}
    BOOST_CHECK(a[mp] == 3);

    it = a.begin();
    BOOST_CHECK(it->second == 2);
    ++it;
    BOOST_CHECK(it->second == 3);

    rit = it;
    BOOST_CHECK(rit->second == 3);
    ++rit;
    BOOST_CHECK(rit->second == 2);

    rit = a.begin();
    BOOST_CHECK(rit->second == 2);
    --rit;
    BOOST_CHECK(rit->second == 3);

    multivector_testT::position_type mpLevel;

    multivector_testT::level_iterator lit = a.begin(mpLevel);
    BOOST_CHECK(lit->second == 2);

    ++lit;
    BOOST_CHECK(lit->second == 3);

    --lit;
    BOOST_CHECK(lit->second == 2);

    mp[0] = 0;
    mp.push_back(0);
    a[mp] = 1; // {{[0], 2}, {[0, 0], 1}, {[1], 3}}
    lit = a.begin(mpLevel);
    BOOST_CHECK(lit->second == 2);

    ++lit;
    BOOST_CHECK(lit->second == 3);

    BOOST_CHECK(lit > a.begin(mpLevel));

    mp.pop_back();
    mp[0] = 2;
    a[mp] = 4; // {{[0], 2}, {[0, 0], 1}, {[1], 3}, {[2], 4}}

    multivector_testT::level_iterator lit2 = a.begin(mpLevel);
    lit = a.begin(mpLevel);

    ++lit2;
    ++lit2;
    ++lit;
    BOOST_CHECK(lit < lit2);

    mp[0] = 0;
    mp.push_back(1);
    a[mp] = 5; // {{[0], 2}, {[0, 0], 1}, {[0, 1], 5}, {[1], 3}, {[2], 4}}

    mpLevel.push_back(0);
    lit = a.begin(mpLevel);
    BOOST_CHECK(lit->second == 1);
    ++lit;
    BOOST_CHECK(lit->second == 5);

    mpLevel.pop_back();
    multivector_testT::level_const_reverse_iterator lrit = a.rbegin(mpLevel);
    int tmp;
    BOOST_CHECK((tmp = lrit->second) == 4);
    ++lrit;
    BOOST_CHECK((tmp = lrit->second) == 3);

    BOOST_CHECK(lrit > a.rbegin(mpLevel));

    multivector_testT::level_const_reverse_iterator lrit2 = a.rbegin(mpLevel);
    lrit = a.rbegin(mpLevel);

    ++lrit2;
    ++lrit2;
    ++lrit;
    BOOST_CHECK(lrit < lrit2);

    mpLevel.push_back(0);
    lrit = a.rbegin(mpLevel);
    BOOST_CHECK(lrit->second == 5);
    ++lrit;
    BOOST_CHECK(lrit->second == 1);
}
